package com.sj.purchase.modules.cost.service.order;

import com.sj.purchase.manager.SkuInfoManager;
import com.sj.purchase.modules.cost.domain.order.Order;
import com.sj.purchase.modules.cost.domain.price.CostPrice;
import com.sj.purchase.modules.cost.service.price.CostPriceService;
import com.sj.purchase.common.utils.mapper.BeanMapper;
import com.sj.purchase.modules.cost.domain.order.OutOrder;
import com.sj.purchase.modules.cost.repository.order.OutOrderRepository;
import com.sj.purchase.modules.cost.utils.DoubleUtil;
import com.sj.purchase.modules.cost.views.order.OutOrderVO;
import com.sj.purchase.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by yangrd on 2017/11/15
 **/
@Service
public class OutOrderService {

    @Autowired
    private OutOrderRepository repository;

    @Autowired
    private SkuInfoManager skuInfoManager;

    @Autowired
    private CostPriceService costPriceService;

    private static List<OutOrderVO> EMPTY_LIST = new ArrayList<>(0);

    public Page<OutOrderVO> findAll(Date startDay, Date endDay, String orderNo, Pageable pageable) {
        Page<OutOrder> outOrderPage = repository.findAll((root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            CriteriaBuilder.In<Order.OrderType> in = cb.in(root.get("type").as(Order.OrderType.class));
            in.value(Order.OrderType.OUT_OTHER).value(Order.OrderType.OUT_SALES);
            predicates.add(in);
            if (Objects.nonNull(startDay)) {
                predicates.add(cb.between(root.get("createDate"), startDay, endDay));
            }
            if (Objects.nonNull(orderNo)) {
                predicates.add(cb.equal(root.get("orderNo"), orderNo));
            }
            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        }, pageable);
        if (outOrderPage.hasContent()) {
            Map<String, List<CostPrice>> skuCostPriceMap = costPriceService.getSkuCostPriceCache(costPriceService.listCostPrice(DateUtils.addDays(startDay, -8), endDay));
            List<OutOrderVO> outOrderVOList = outOrderPage.getContent().stream().map(outOrder -> conversion(outOrder, skuCostPriceMap)).collect(Collectors.toList());
            return new PageImpl<>(outOrderVOList, pageable, outOrderPage.getTotalElements());
        } else {
            return new PageImpl<>(EMPTY_LIST);
        }

    }

    private OutOrderVO conversion(OutOrder outOrder, Map<String, List<CostPrice>> skuCostPriceMap) {
        OutOrderVO outOrderVO = BeanMapper.map(outOrder, OutOrderVO.class);
        outOrderVO.getOrderItems().forEach(outOrderItemVO -> {
            String skuNo = outOrderItemVO.getSkuNo();
            Date orderDate = outOrderVO.getCreateDate();
            Long num = outOrderItemVO.getNum();

            String skuName = skuInfoManager.getSkuInfo(skuNo).getSkuname();
            Double costPrice = costPriceService.getCostPrice(skuCostPriceMap, skuNo, orderDate);
            Double price = Optional.ofNullable(outOrderItemVO.getPrice()).orElseGet(() -> 0D);

            outOrderItemVO.setSkuName(skuName);
            outOrderItemVO.setCostPrice(DoubleUtil.format(costPrice));
            outOrderItemVO.setProfit(DoubleUtil.format((price - costPrice)) * num);
        });
        String orderType = outOrder.getType().equals(Order.OrderType.OUT_SALES) ? "销售出库" : "其他出库";
        Double costPrice = outOrderVO.getOrderItems().stream().mapToDouble(item -> item.getNum() * item.getCostPrice()).sum();

        Double payment = outOrder.getPayment();
        if (payment == null) {
            payment = 0D;
        }

        Double profit = payment - costPrice;
        return outOrderVO.setOrderType(orderType).setCostPrice(DoubleUtil.format(costPrice)).setProfit(DoubleUtil.format(profit));
    }

}
